Skip to content

S01-13 JavaSE-枚举和注解

[TOC]

需求场景

创建季节(Season)对象,要求:

  • 季节对象固定(春、夏、秋、冬)
  • 只读,不能修改

问题分析

  1. 季节值是有限的4个
  2. 需要只读属性,不能修改
  3. 传统类设计无法保证对象唯一性

解决方案-枚举

  1. 枚举(enumeration,简写enum)是一组常量的集合
  2. 枚举属于特殊类,仅包含有限的特定对象

枚举的两种实现方式

  1. 自定义类实现枚举
  2. 使用enum关键字实现枚举

自定义类实现枚举-应用案例

java
package com.hspedu.enum_;

/**
 * 自定义枚举类实现
 */
public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season.AUTUMN);
        System.out.println(Season.SPRING);
    }
}

class Season { // 枚举类
    private String name;
    private String desc; // 描述

    // 1. 私有构造器,防止直接new
    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    // 2. 本类内部创建固定对象
    public static final Season SPRING = new Season("春天", "温暖");
    public static final Season SUMMER = new Season("夏天", "炎热");
    public static final Season AUTUMN = new Season("秋天", "凉爽");
    public static final Season WINTER = new Season("冬天", "寒冷");

    // 3. 提供get方法,无set方法(只读)
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

自定义类实现枚举-小结

  1. 构造器私有化
  2. 本类内部创建固定对象
  3. 对外暴露对象(public final static修饰)
  4. 提供get方法,不提供set方法

enum关键字实现枚举-快速入门

java
package com.hspedu.enum_;

/**
 * 使用enum关键字实现枚举
 */
public class Enumeration03 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        System.out.println(Season2.SUMMER);
    }
}

// 枚举类
enum Season2 {
    // 枚举对象(必须放在行首),多个用逗号分隔,末尾可加封号
    SPRING("春天", "温暖"),
    SUMMER("夏天", "炎热"),
    AUTUMN("秋天", "凉爽"),
    WINTER("冬天", "寒冷");

    private String name;
    private String desc;

    // 构造器(私有,默认可以省略private)
    Season2(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    // 无参构造器(如果需要)
    private Season2() {}

    // get方法
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

enum关键字实现枚举注意事项

  1. enum类默认继承Enum类,且是final类(不能被继承)
  2. 传统public static final Season SPRING = new Season(...)简化为SPRING(...)
  3. 无参构造器创建枚举对象时,可省略()
  4. 多个枚举对象用逗号分隔,末尾加分号
  5. 枚举对象必须放在枚举类行首

enum关键字实现枚举-课堂练习

练习1

java
// 代码是否正确? 含义是什么?
enum Gender{
    BOY, GIRL; // 调用无参构造器
}
  • 语法正确
  • 枚举类Gender,无属性
  • 两个枚举对象BOY、GIRL(无参构造器创建)

练习2

java
enum Gender2{
    BOY,GIRL;
}

public class Test {
    public static void main(String[] args) {
        Gender2 boy = Gender2.BOY;
        System.out.println(boy); // 输出BOY(调用父类Enum的toString())
        Gender2 boy2 = Gender2.BOY;
        System.out.println(boy2 == boy); // True(同一对象)
    }
}

enum常用方法说明

enum类隐式继承Enum类,可使用以下常用方法:

方法名详细描述
valueOf传递枚举类型Class和常量名,返回匹配的枚举常量
toString返回当前枚举常量名称(可重写)
equals直接使用==比较,用于集合中
hashCode与equals保持一致,不可变
getDeclaringClass获取枚举常量所属的枚举类Class对象
name返回枚举常量名称(不可重写)
ordinal返回枚举常量的次序(从0开始)
compareTo比较两个枚举常量的次序(编号差值)
clone不可克隆,抛出CloneNotSupportedException

方法应用实例(EnumMethod.java)

java
package com.hspedu.enum_;

/**
 * 演示Enum类常用方法
 */
public class EnumMethod {
    public static void main(String[] args) {
        Season2 autumn = Season2.AUTUMN;

        // 1. name():返回枚举对象名称
        System.out.println(autumn.name()); // AUTUMN

        // 2. ordinal():返回次序(从0开始)
        System.out.println(autumn.ordinal()); // 2

        // 3. values():返回所有枚举对象数组
        Season2[] values = Season2.values();
        System.out.println("===遍历枚举对象===");
        for (Season2 season : values) {
            System.out.println(season);
        }

        // 4. valueOf():将字符串转为枚举对象
        Season2 autumn1 = Season2.valueOf("AUTUMN");
        System.out.println("autumn1=" + autumn1);
        System.out.println(autumn == autumn1); // True

        // 5. compareTo():比较次序差值
        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER)); // 2-3=-1
    }
}

enum常用方法课堂练习

需求

声明Week枚举类,包含星期一至星期日,使用values()遍历输出。

代码实现

java
package com.hspedu.enum_;

public class EnumExercise02 {
    public static void main(String[] args) {
        // 获取所有枚举对象
        Week[] weeks = Week.values();
        System.out.println("===所有星期的信息如下===");
        for (Week week : weeks) {
            System.out.println(week);
        }
    }
}

enum Week {
    MONDAY("星期一"),
    TUESDAY("星期二"),
    WEDNESDAY("星期三"),
    THURSDAY("星期四"),
    FRIDAY("星期五"),
    SATURDAY("星期六"),
    SUNDAY("星期日");

    private String name;

    // 构造器
    private Week(String name) {
        this.name = name;
    }

    // 重写toString()
    @Override
    public String toString() {
        return name;
    }
}

enum实现接口

  1. enum类不能继承其他类(已隐式继承Enum)
  2. 枚举类可以实现接口,与普通类实现接口语法一致

代码示例

java
package com.hspedu.enum_;

public class EnumDetail {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing();
    }
}

// 接口
interface IPlaying {
    void playing();
}

// 枚举类实现接口
enum Music implements IPlaying {
    CLASSICMUSIC;

    @Override
    public void playing() {
        System.out.println("播放好听的音乐...");
    }
}

注解的理解

  1. 注解(Annotation)又称元数据,用于修饰解释程序元素(包、类、方法等)
  2. 不影响程序逻辑,但可被编译或运行
  3. JavaSE中用途:标记过时功能、忽略警告等
  4. JavaEE中用途:配置应用、替代XML配置等

基本的Annotation介绍

使用Annotation时需加@符号,作为修饰符使用。

三个基本Annotation

  1. @Override:限定方法重写父类方法,仅用于方法
  2. @Deprecated:标记程序元素已过时
  3. @SuppressWarnings:抑制编译器警告

基本的Annotation应用案例

@Override注解(Override_.java)

java
package com.hspedu.annotation_;

public class Override_ {
    public static void main(String[] args) {
    }
}

class Father { // 父类
    public void fly() {
        System.out.println("Father fly...");
    }

    public void say() {}
}

class Son extends Father { // 子类
    // @Override 表示重写父类方法
    @Override
    public void fly() {
        System.out.println("Son fly....");
    }

    @Override
    public void say() {}
}

注意事项

  • 编译器会检查是否真的重写了父类方法
  • 仅能修饰方法
  • 源码:@Target(ElementType.METHOD)

@Deprecated注解(Deprecated_.java)

java
package com.hspedu.annotation_;

public class Deprecated_ {
    public static void main(String[] args) {
        A a = new A();
        a.hi(); // 警告:方法已过时
        System.out.println(a.n1); // 警告:字段已过时
    }
}

@Deprecated // 类已过时
class A {
    @Deprecated // 字段已过时
    public int n1 = 10;

    @Deprecated // 方法已过时
    public void hi() {}
}

注意事项

  • 可修饰类、方法、字段、包、参数等
  • 用于版本升级过渡
  • 源码:@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})

@SuppressWarnings注解(SuppressWarnings_.java)

java
package com.hspedu.annotation_;

import java.util.ArrayList;
import java.util.List;

// 抑制多种警告
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
public class SuppressWarnings_ {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        int i; // 未使用但无警告
        System.out.println(list.get(1));
    }

    public void f1() {
        @SuppressWarnings({"rawtypes"})
        List list = new ArrayList();
        list.add("jack");
    }
}

常用抑制类型

  • all:抑制所有警告
  • rawtypes:抑制未指定泛型的警告
  • unchecked:抑制未检查的警告
  • unused:抑制未使用变量的警告

JDK的元Annotation(了解)

元Annotation用于修饰其他Annotation,共4种:

元注解作用
Retention指定注解的作用范围(SOURCE/CLASS/RUNTIME)
Target指定注解可修饰的程序元素
Documented指定注解是否在javadoc中体现
Inherited子类继承父类的注解

@Retention

  • RetentionPolicy.SOURCE:编译器使用后丢弃(如@Override)
  • RetentionPolicy.CLASS:记录在class文件中,JVM不保留(默认)
  • RetentionPolicy.RUNTIME:记录在class文件中,JVM保留,可通过反射获取

@Target

指定注解可修饰的程序元素(如METHOD、TYPE、FIELD等)

第10章作业

代码执行结果题(Homework01.java)

java
class Car {
    static String color = "white";
    double price = 10;

    public Car() {
        this.price = 9;
        this.color = "red";
    }

    public Car(double price) {
        this.price = price;
    }

    public String toString() {
        return price + "\t" + color;
    }
}

public class Homework01 {
    public static void main(String[] args) {
        Car c1 = new Car(100);
        System.out.println(c1); // 100.0	red
        Car c = new Car();
        System.out.println(c); // 9.0	red
    }
}

编程题(Homework02.java)- 衣服序列号生成

java
package com.hspedu.homework;

public class Homework02 {
    public static void main(String[] args) {
        // 测试getNextNum方法
        System.out.println(Frock.getNextNum()); // 100100
        System.out.println(Frock.getNextNum()); // 100200

        // 测试三个Frock对象
        Frock f1 = new Frock();
        Frock f2 = new Frock();
        Frock f3 = new Frock();
        System.out.println(f1.getSerialNumber()); // 100300
        System.out.println(f2.getSerialNumber()); // 100400
        System.out.println(f3.getSerialNumber()); // 100500
    }
}

class Frock {
    // 私有静态属性:序列号起始值
    private static int currentNum = 100000;
    // 序列号属性
    private int serialNumber;

    // 构造器:获取唯一序列号
    public Frock() {
        this.serialNumber = getNextNum();
    }

    // 静态方法:生成下一个序列号
    public static int getNextNum() {
        currentNum += 100;
        return currentNum;
    }

    // get方法
    public int getSerialNumber() {
        return serialNumber;
    }
}

编程题(Homework03.java)- 抽象类使用

java
package com.hspedu.homework;

public class Homework03 {
    public static void main(String[] args) {
        Animal cat = new Cat();
        cat.shout(); // 猫会喵喵叫
        Animal dog = new Dog();
        dog.shout(); // 狗会汪汪叫
    }
}

// 抽象动物类
abstract class Animal {
    public abstract void shout();
}

// 猫类
class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫会喵喵叫");
    }
}

// 狗类
class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗会汪汪叫");
    }
}

编程题(Homework04.java)- 匿名内部类使用

java
package com.hspedu.homework;

public class Homework04 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        // 测试计算功能:10+20
        cellphone.testWork(new Calculator() {
            @Override
            public double work(double n1, double n2) {
                return n1 + n2;
            }
        }, 10, 20);

        // 测试计算功能:50-30
        cellphone.testWork(new Calculator() {
            @Override
            public double work(double n1, double n2) {
                return n1 - n2;
            }
        }, 50, 30);
    }
}

// 计算器接口
interface Calculator {
    double work(double n1, double n2);
}

// 手机类
class Cellphone {
    // 测试计算功能
    public void testWork(Calculator calculator, double n1, double n2) {
        double result = calculator.work(n1, n2);
        System.out.println("计算结果:" + result);
    }
}

编程题(Homework05.java)- 局部内部类

java
package com.hspedu.homework;

public class Homework05 {
    public static void main(String[] args) {
        A a = new A();
        a.m1();
    }
}

class A {
    private String name = "外部类A的name";

    public void m1() {
        // 局部内部类B
        class B {
            private final String name = "局部内部类B的name";

            public void show() {
                // 打印内部类和外部类的name
                System.out.println("内部类name:" + name);
                System.out.println("外部类name:" + A.this.name);
            }
        }

        // 创建B对象并调用方法
        B b = new B();
        b.show();
    }
}

编程题(Homework06.java)- 工厂模式+接口

java
package com.hspedu.homework;

public class Homework06 {
    public static void main(String[] args) {
        // 实例化唐僧
        Person tangseng = new Person("唐僧", VehicleFactory.getHorse());
        tangseng.useVehicle(); // 使用马匹

        // 遇到大河,切换交通工具
        tangseng.setVehicles(VehicleFactory.getBoat());
        tangseng.useVehicle(); // 使用船只
    }
}

// 交通工具接口
interface Vehicles {
    void work();
}

// 马匹类
class Horse implements Vehicles {
    @Override
    public void work() {
        System.out.println("马匹奔跑...");
    }
}

// 船只类
class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println("船只航行...");
    }
}

// 交通工具工厂类
class VehicleFactory {
    // 获取马匹
    public static Vehicles getHorse() {
        return new Horse();
    }

    // 获取船只
    public static Vehicles getBoat() {
        return new Boat();
    }
}

// 人类
class Person {
    private String name;
    private Vehicles vehicles;

    // 构造器
    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }

    // 使用交通工具
    public void useVehicle() {
        System.out.println(name + "使用");
        vehicles.work();
    }

    // setter方法
    public void setVehicles(Vehicles vehicles) {
        this.vehicles = vehicles;
    }
}

编程题(Homework07.java)- 成员内部类

java
package com.hspedu.homework;

public class Homework07 {
    public static void main(String[] args) {
        // 测试不同温度
        Car car1 = new Car(50);
        car1.getAir().flow(); // 吹冷气

        Car car2 = new Car(-5);
        car2.getAir().flow(); // 吹暖气

        Car car3 = new Car(25);
        car3.getAir().flow(); // 关闭空调
    }
}

class Car {
    private double temperature; // 温度
    // 成员内部类:空调
    class Air {
        public void flow() {
            if (temperature > 40) {
                System.out.println("温度超过40度,吹冷气");
            } else if (temperature < 0) {
                System.out.println("温度低于0度,吹暖气");
            } else {
                System.out.println("温度适宜,关闭空调");
            }
        }
    }

    // 构造器
    public Car(double temperature) {
        this.temperature = temperature;
    }

    // 获取空调对象
    public Air getAir() {
        return new Air();
    }
}

编程题(Homework08.java)- 枚举类

java
package com.hspedu.homework;

public class Homework08 {
    public static void main(String[] args) {
        // 测试show方法
        for (Color color : Color.values()) {
            color.show();
        }

        // switch中使用枚举
        Color color = Color.RED;
        switch (color) {
            case RED:
                System.out.println("选中红色");
                break;
            case BLUE:
                System.out.println("选中蓝色");
                break;
            case BLACK:
                System.out.println("选中黑色");
                break;
            case YELLOW:
                System.out.println("选中黄色");
                break;
            case GREEN:
                System.out.println("选中绿色");
                break;
        }
    }
}

// 接口
interface ShowColor {
    void show();
}

// 颜色枚举类
enum Color implements ShowColor {
    // 枚举对象及属性值
    RED(255, 0, 0),
    BLUE(0, 0, 255),
    BLACK(0, 0, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0);

    // 属性
    private int redValue;
    private int greenValue;
    private int blueValue;

    // 构造器
    Color(int redValue, int greenValue, int blueValue) {
        this.redValue = redValue;
        this.greenValue = greenValue;
        this.blueValue = blueValue;
    }

    // 实现接口方法
    @Override
    public void show() {
        System.out.println("颜色RGB值: " + redValue + "," + greenValue + "," + blueValue);
    }
}